import tornado.websocket
from tornado import httpserver
import tornado.ioloop
import tornado.web
import json
import threading
import os
import requests
import redis
import time
# from base import WsBaseHandler, BaseHandler

import asyncio

def ret_json(mydict):
    # indent 缩进方式
    res = json.dumps(mydict, ensure_ascii=False, default=str, indent=4)

    return res


# 声明基类
class BaseHandler(tornado.web.RequestHandler):

    # 重写父类方法
    def set_default_headers(self):
        # 设置请求头信息
        print("开始设置")
        # 域名信息
        self.set_header("Access-Control-Allow-Origin", "*")
        # 请求信息
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        # 请求方式
        self.set_header("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE")

        self.set_header('Access-Control-Allow-Headers', 'Content-Type')

        self.set_header('Content-Type', 'application/json; charset=UTF-8')

        print('头部设置成功')

    def post(self):
        self.write('这里是post请求')

    def get(self):
        self.write('这里是get请求')

    def delete(self):
        self.write('这里是delete请求')

    def put(self):
        self.write('这里是put请求')

    def options(self, *args):
        # 设置状态码
        self.set_status(204)
        # 设置拦截
        self.finish()



# from tools import *
# from test_queue import MysqlDb

# 导入栈
# from test_stack import MyStack

# 导入异步写入文件
# from test_aiofile import write_file

# 分库存入消息
# from docker_redis import MyStacks

# python内置装饰器库
# from functools import wraps

# # 删除最早信息   延时任务
# from delay_chat_out import Delay_out


# 导入机器人回复
from talk_robot import qinyunke

# 导入情感分析接口
# from test_sentiment import sentiment

# 导入封装的情感分析接口
# from baiduaip import BaiduAip

# 导入绘图排行榜方法
# from test_mat import plt_png

static_path = os.path.join(os.path.dirname(__file__), "static")


# # 限流装饰器
# def restriction_request(func):
#     @wraps(func)
#     def wrapper(self, *args, **kwargs):
#
#         id = self.get_argument('id', None)
#         r = redis.Redis(decode_responses=True)
#         key = 'text' + str(id)
#         num = r.get(key)
#         a = r.ttl(key)
#         if num:
#             if int(num) >= 100:
#                 return self.write(ret_json({'code': 403, 'meg': '剩余%s秒重试' % a}))
#             else:
#                 r.incr(key)
#         else:
#             r.setex(key, 60, 1)
#         return func(self, *args, **kwargs)
#
#     return wrapper
#
#
# r = redis.Redis(decode_responses=True)
#
#
# def pass_slide_window(func):
#     @wraps(func)
#     def wrapper(self, *args, **kwargs):
#
#         uid = self.get_argument('id', None)
#
#         print(uid, 'uid')
#         # uid = 3   # 测试
#         time_zone = 30
#         times = 5
#
#         # 获取当前时间时间戳
#         now_ts = time.time() * 1000
#
#         # 集合的   value
#         value = now_ts
#
#         # 算滑动窗口的左边界时间
#
#         old_ts = now_ts - (time_zone * 1000)
#
#         # 删除窗口之前的历史数据
#         r.zremrangebyscore(uid, 0, old_ts)
#
#         # 获取请求次数(获取集合的长度)
#         count = r.zcard(uid)
#
#         # 判断
#         if not count or count < times:
#             # 入库
#             r.zadd(uid, {value: now_ts})
#
#             # 设置生命周期
#             r.expire(uid, time_zone + 1)
#
#             return self.write(ret_json({'code': 200, 'meg': 'OK'}))
#
#         else:
#
#             # return self.write('限流')
#             return self.write(ret_json({'code': 403, 'meg': '您的访问过于频繁'}))
#
#     return wrapper
#
#
# # 固定窗口限流装饰器
# def pass_window(func):
#     @wraps(func)
#     def wrapper(self, *args, **kwargs):
#         # 用户
#         uid = self.get_argument('id', None)
#         # 秒
#         time_zone = 20
#         # 限制个数
#         times = 3
#
#         # 获取计数器
#         count = r.get(uid)
#         print(count,'装饰器')
#
#         if not count:
#             count = 1
#
#             # set expire  两个操作中间有空隙
#             # setex(合体)  没有时间空隙
#
#             r.setex(uid, time_zone, count)
#
#         print(count)
#
#         if int(count) < times:
#
#             r.incr(uid)
#
#             print('继续执行')
#
#             response = func(self, *args, **kwargs)
#
#             return response
#         else:
#
#             print('您的访问过于频繁')
#
#     return wrapper
#
#
# # 文件上传
# class Upload(BaseHandler):
#
#     async def post(self):
#         file = self.request.files['file']
#
#         type = self.get_argument('type', None)
#
#         for meta in file:
#             filename = meta['filename']
#
#             with open('./static/' + filename, 'wb') as f:
#                 f.write(meta['body'])
#
#             if type == 'audit':
#                 return self.write(ret_json({'code': 200, 'meg': '上传审批成功', 'filename': filename}))
#
#             else:
#                 return self.write(ret_json({'code': 200, 'meg': '上传广告素材成功', 'filename': filename}))
#
#
users = []
#
#
# # channels = ['channel_1', 'channel_2']
#
#
# class Msgl:
#     # 记录当前的链接用户
#     def user_connect(self, user):
#
#         r = redis.Redis(decode_responses=True)
#
#         channel = user.get_cookie('channel')
#
#         x = r.hget('channels', channel)
#
#         if not x:
#             r.hset('channels', channel, 1)
#
#         get_channel = r.hget('channels', channel)
#
#         if int(get_channel) < 2:
#             users.append(user)
#             r.hset('channels', channel, (int(get_channel) + 1))
#         else:
#             user.write_message('客服正忙稍后再试')
#
#     # 断开链接
#     def user_del(self, user):
#         r = redis.Redis(decode_responses=True)
#
#         get_channel = r.hget('channels', user.get_cookie('channel'))
#
#         r.hset('channels', user.get_cookie('channel'), (int(get_channel) - 1))
#
#         users.remove(user)
#
#     # 发消息
#     def send(self, message):
#         for user in users:
#             user.write_message({'msg': message})
#
#
# class WB(tornado.websocket.WebSocketHandler):
#     # 跨域支持
#     def check_origin(self, origin):
#         return True
#
#     # 开启链接
#     def open(self):
#         # users.append(self)
#         # for i in users:
#         #     # print(i)
#         #     print(i.get_cookie('channel'), '你好')
#         Msgl().user_connect(self)
#
#     # 接收消息
#     def on_message(self, message):
#         # print(message)
#         self.write_message(message)
#
#     # 断开
#     def on_close(self):
#         Msgl().user_del(self)


# # # 主动推送消息接口
# class Push(BaseHandler):
#
#     async def post(self):
#         msg = self.get_argument('msg', None)
#         Msgl().send(msg)
#         # print(msg)
#         return self.write(ret_json({'msg': msg}))


# # 基于redis监听发布者发布消息
def redis_listener(loop):

    asyncio.set_event_loop(loop)

    async def lis():
        r = redis.Redis(decode_responses=True)

        # 声名pubsub实例
        ps = r.pubsub()

        # 订阅聊天室频道
        channels = r.lrange('channel', 0, -1)

        ps.subscribe(channels)

        # 监听
        for message in ps.listen():
            # 循环用户列表
            for i in users:
                # print(message, 'message信息', '--------', i.get_cookie('channel'))
                if message['type'] == "message" and i.get_cookie('channel') == message['channel']:
                    print('进')

                    # requests.post("http://localhost:8000/push/", data={'msg': message['data']})

    future = asyncio.gather(lis())
    loop.run_until_complete(future)

# 接口 发布消息
class Msg(BaseHandler):

    # 发布信息
    # @pass_window  # 固定窗口限流
    # @pass_slide_window
    # async def post(self):
    #     data = self.get_argument('data', None)
    #
    #     channel = self.get_argument('channel', None)
    #
    #     # print(data,channel,type(data),type(channel))
    #
    #     r = redis.Redis(decode_responses=True)
    #
    #     res = r.lrange('channel', 0, -1)
    #     if channel not in res:
    #         r.lpush('channel', channel)
    #     else:
    #         pass
    #
    #     # 发布消息
    #     r.publish(channel, data)
    #     # 单个
    #     # mystack = MyStack()
    #     # 多个库
    #     mystacks = MyStacks()
    #     data1 = json.loads(data)
    #     data1['time'] = time.time()
    #     data1 = json.dumps(data1)
    #     # 单个
    #     # mystack.push('send', data1)
    #     # 多个库
    #     mystacks.push(channel, data1)
    #     uid = channel.split('_')[-1]
    #     info = eval(data)
    #     if uid == info['uid']:
    #         print('进')
    #         with open('test.txt', 'a', encoding='utf-8') as f:
    #             f.write(data + '\n')
    #             mysql = MysqlDb()
    #             # 导入模块
    #             state = sentiment(info['send']['filename'])
    #
    #             # 使用自己封装的
    #             # 实例
    #             baidu = BaiduAip()
    #             # 情感分析
    #             state = baidu.sentiment(info['send']['filename'])
    #             # print(state)
    #             mysql.insert("insert into `client_stiment` (text,stimen,uid) values ('%s',%s,%s)" %
    #                          (info['send']['filename'], state, info['uid']))
    #             # 标签抽取
    #             baidu = BaiduAip()
    #             ret = baidu.comment(info['send']['filename'], 8)
    #             if ret is not None:
    #                 print(ret)
    #                 for i in ret:
    #                     # print(i['adj'],'斤+++++++++')
    #                     res = mysql.read("select * from `tag` where `title` = '%s'" % i['adj'])
    #                     if res:
    #
    #                         mysql.insert("insert into `user_tag` (uid,tag_id) values (%s,%s)" % (info['uid'], res['id']))
    #
    #                     else:
    #                         mysql.insert("insert into `tag` (title) values ('%s')" % i['adj'])
    #                         res = mysql.read("select * from `tag` where `title` = '%s'" % i['adj'])
    #                         print(res)
    #                         mysql.insert("insert into `user_tag` (uid,tag_id) values (%s,%s)" % (info['uid'], res['id']))
    #
    #     # 延迟队列删除最早的信息
    #     # Delay_out().add(id)
    #
    #     return self.write({"code": 200, "msg": data})
    #
    # # 获取数据
    # # @pass_window
    # # @pass_slide_window
    # async def get(self):
    #     # mystack = MyStack()
    #     # res = mystack.lrange('send')
    #
    #     channel = self.get_argument('channel', None)
    #
    #     id = self.get_argument('id', None)
    #
    #     mystacks = MyStacks()
    #
    #     res = mystacks.lrange(channel)
    #
    #     list1 = []
    #     for i in json.loads(res):
    #         # print(i)
    #
    #         if int(i['time']) + 30 > int(time.time()):
    #
    #             i['state'] = 1
    #
    #             list1.append(i)
    #         else:
    #             list1.append(i)
    #
    #     return self.write(ret_json(list1))

    # 机器人对话存储
    async def put(self):
        data = self.get_argument('data', None)
        user = self.get_argument('user', None)
        id = self.get_argument('id', None)
        res = qinyunke(data)

        r = redis.Redis(decode_responses=True)
        print(res,id, '机器人')

        r.lpush('robot%s' % id, str({'user': user, 'send': data}))
        r.lpush('robot%s' % id, str({'user': '机器人', 'send': res}))

        return self.write(ret_json({'code': 200, 'meg': res}))

    # 获取与机器之前的对话信息
    async def delete(self):
        id = self.get_argument('id', None)

        r = redis.Redis(decode_responses=True)

        res = r.lrange('robot%s' % id, 0, -1)

        res = [eval(i) for i in res]

        res.reverse()

        return self.write(ret_json(res))


# class Sends(BaseHandler):
#     async def post(self):
#         channel = self.get_argument('channel', None)
#
#         id = self.get_argument('id', None)
#
#         mystacks = MyStacks()
#         mystacks.pop(channel, id)
#
#         return self.write({"code": 200, "msg": 'ok'})
#
#     async def get(self):
#         data = self.get_argument('data', None)
#         # print(data)
#         return self.write(ret_json({'code': 200, 'meg': data}))

#
# class Room(BaseHandler):
#     async def get(self):
#         r = redis.Redis(decode_responses=True)
#         res = r.lrange('channel', 0, -1)
#         return self.write(ret_json(res))
#
#     async def post(self):
#         r = redis.Redis(decode_responses=True)
#         channel = r.lrange('channel', 0, -1)
#         mysql = MysqlDb()
#         for i in channel:
#             i = i.split('_')[-1]
#             res = 'select a.username,b.tag_id,count(b.tag_id) as count ,c.title from `user` a inner join `user_tag` b on a.id=b.uid inner join `tag` c on b.tag_id=c.id where a.id=%s group by b.tag_id' % int(i)
#
#             info = mysql.read_list(res)
#
#             print(info)
#         return self.write(ret_json({'code': 200, 'meg': 'a'}))
#
#     async def put(self):
#         r = redis.Redis(decode_responses=True)
#         channel = r.lrange('channel', 0, -1)
#         mysql = MysqlDb()
#         for i in channel:
#             i = i.split('_')[-1]
#             res = "select case a.stimen when 0 then '正向' when 1 then '中性' when 2 then '负向' end stimen,count(*),`user`.username from client_stiment as a INNER JOIN `user` on a.uid = `user`.id where uid = %s group by a.stimen" % int(i)
#
#             info = mysql.read_list(res)
#
#             print(info)
#         return self.write(ret_json({'code': 200, 'meg': 'a'}))
#
# class Rank(BaseHandler):
#     async def get(self):
#         mysql = MysqlDb()
#         # 当天分数
#         sql = "select sum(stimen) as sum,uid,b.username from client_stiment as a inner join user as b on a.uid = b.id  where to_days(date) = to_days(now()) group by uid order by sum desc;"
#
#         day = mysql.read_list(sql)
#         if day:
#             admin = []
#             data = []
#             for i in day:
#                 admin.append(i['username'])
#                 data.append(int(i['sum']))
#
#             plt_png(admin, data, '分数排行', '%s分析柱状表' % datetime.datetime.now().strftime('%Y-%m-%d'), '分数', '用户名', '当天分数图')
#
#     async def post(self):
#         # 一周之内的分数
#         week = "select a.uid,b.username,a.avg,a.score,a.day from(select uid,avg(stimen)as avg,sum(stimen) as score,count(distinct day) as day from client_stiment where YEARWEEK(DATE_FORMAT(date,'%Y-%m-%d')) = YEARWEEK(NOW()) group by uid) as a inner join user as b on a.uid = b.id where a.day >= 4 order by a.score desc;"
#         mysql = MysqlDb()
#         get_week = mysql.read_list(week)
#         if get_week:
#             admin = []
#             data = []
#             for i in get_week:
#                 admin.append(i['username'])
#
#                 # 一周之内总分数
#                 data.append(int(i['score']))
#
#             plt_png(admin, data, '周总分数排行', '12.20-12.24分析柱状表', '分数', '用户名', '周总分分数图')
#
#     async def delete(self):
#         # 一周之内的分数
#         week = "select a.uid,b.username,a.avg,a.score,a.day from(select uid,avg(stimen)as avg,sum(stimen) as score,count(distinct day) as day from client_stiment where YEARWEEK(DATE_FORMAT(date,'%Y-%m-%d')) = YEARWEEK(NOW()) group by uid) as a inner join user as b on a.uid = b.id where a.day >= 4 order by a.avg desc;"
#         mysql = MysqlDb()
#         get_week = mysql.read_list(week)
#         print(get_week)
#         if get_week:
#             admin = []
#             data = []
#             for i in get_week:
#                 admin.append(i['username'])
#                 # 一周平均分数
#                 data.append(float(i['avg']))
#             # print(data)
#             plt_png(admin, data, '周平均分数排行', '12.20-12.24分析柱状表', '分数', '用户名', '周平均分分数图')
#
#     async def put(self):
#         # 一个月之内的分数  (uid/username/总分数/平均分数/总天数)
#         month = "select a.uid,b.username,a.score,a.avg,a.day from (select count(distinct day) as day,uid,sum(stimen) as score,avg(stimen) as avg from client_stiment where DATE_FORMAT(date,'%Y%m') = DATE_FORMAT(CURDATE(),'%Y%m') group by uid) as a inner join user as b on a.uid = b.id where a.day >= 24 order by a.avg desc ;"
#         mysql = MysqlDb()
#         get_month = mysql.read_list(month)
#         print(get_month)
#
#         if get_month:
#             admin = []
#             data = []
#             for i in get_month:
#                 admin.append(i['username'])
#                 # 一月平均分数
#                 data.append(int(i['avg']))
#                 # 一月之内总分数
#                 # data.append(int(i['score']))
#                 print(i)
#             print(admin, data)
#             plt_png(admin, data, '月平均分数排行', '12月分析柱状表', '分数', '用户名', '月平均分分数图')
#             # plt_png(admin, data, '月总分数排行', '12月分析柱状表', '分数', '用户名', '月总分分数图')


# 建立tornado实例
app = tornado.web.Application(
    [
        (r'/send/', Msg),
        # (r'/sends/', Sends),
        # (r'/room/', Room),
        # (r'/wb/', WB),
        # # (r'/ws/',WsHandler),
        # (r'/push/', Push),
        # (r'/upload/', Upload),
        # (r'/rank/', Rank),
    ],
    static_path=static_path,
    # debug=True

)

if __name__ == '__main__':
    # 单线程启动订阅者服务
    # threading.Thread(target=redis_listener).start()
    #
    # 声名服务器
    # server = httpserver.HTTPServer(app)
    #
    # 监听端口
    # server.listen(8000)
    # 开启事件循环
    # tornado.ioloop.IOLoop.instance().start()

    # loop = async
    # 单线程启动订阅者服务
    thread_loop = asyncio.new_event_loop()

    thread = threading.Thread(target=redis_listener, args=(thread_loop,)).start()
    # thread.daemon = True

    # redis_listener()

    # 声明服务器
    http_server = tornado.httpserver.HTTPServer(app)

    # 监听端口
    http_server.listen(8000)
    print("服务启动中")
    # 开启事件循环
    tornado.ioloop.IOLoop.instance().start()


